/*
 * This source code is part of TWaver 4.0
 *
 * Serva Software PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 * Copyright 2002 - 2011 Serva Software. All rights reserved.
 */

package demo.network.miscellaneous.map;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Hashtable;
import java.util.List;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import twaver.Element;
import twaver.ElementCallbackHandler;
import twaver.Generator;
import twaver.MovableFilter;
import twaver.ResizableFilter;
import twaver.TDataBox;
import twaver.TUIManager;
import twaver.TWaverConst;
import twaver.network.InteractionModeFactory;
import twaver.network.TNetwork;
import twaver.network.background.ColorBackground;
import demo.DemoPane;

public class MapDemo extends DemoPane {

	static {
		TUIManager.registerAttachment("stateinfo", MapInfoAttachment.class);
	}

	private TDataBox box = new TDataBox();
	private TNetwork network = new TNetwork(box);
	private MapNode lastNode = null;
	private boolean editable = false;
	private Color renderColor = new Color(0, 100, 150, 200);
	private Color outlineColor = new Color(250, 240, 200);

	public MapDemo() {
		initGUI();
		initNetwork();
		loadXML();
	}

	public void loadXML() {
		box.clear();
		List list = MapXMLUtil.parserXml("/demo/network/miscellaneous/map/map.xml", 30, 30);
		box.addElements(list);
	}

	private void initGUI() {
		final JPanel zoomPanel = createZoomPanel();
		zoomPanel.setBounds(10, 480, 60, 150);
		final MapControlPanel controlPanel = new MapControlPanel(this);
		controlPanel.setBounds(360, 405, 180, 120);
		network.getLayeredPane().add(zoomPanel, new Integer(2));
		network.getLayeredPane().add(controlPanel, new Integer(2));
		this.setLayout(new BorderLayout());
		this.add(network, BorderLayout.CENTER);
		this.addComponentListener(new ComponentAdapter() {
			public void componentResized(ComponentEvent e) {
				zoomPanel.setBounds(10, getHeight() - 165, 60, 150);
				controlPanel.setBounds(getWidth() - 200, getHeight() - 140, 180, 120);
			}

			public void componentShown(ComponentEvent e) {
				zoomPanel.setBounds(10, getHeight() - 165, 60, 150);
				controlPanel.setBounds(getWidth() - 200, getHeight() - 140, 180, 120);
			}
		});
	}

	private JPanel createZoomPanel() {
		JPanel panel = new JPanel(new BorderLayout());
		panel.setOpaque(false);
		final JSlider slider = new JSlider();
		slider.setMaximum(500);
		slider.setMinimum(0);
		slider.setMajorTickSpacing(100);
		slider.setPaintLabels(true);
		slider.setPaintTicks(true);
		slider.setOpaque(false);
		slider.setOrientation(JSlider.VERTICAL);
		panel.add(slider);
		int max = slider.getMaximum();
		int min = slider.getMinimum();
		int gap = slider.getMajorTickSpacing();
		int size = (max - min) / gap;
		Hashtable list = new Hashtable();
		for (int i = 0; i < size + 1; i++) {
			JLabel label = new JLabel(i * 100 + "%");
			label.setFont(new Font("Dialog", Font.ITALIC, 9));
			list.put(new Integer(i * 100), label);
		}
		slider.setLabelTable(list);
		slider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				network.getZoomer().setZoom(slider.getValue() / 100.0);
			}
		});
		slider.setValue((int) (network.getZoom() * 100));
		return panel;
	}

	private void initNetwork() {
		network.setToolbar(null);
		network.setInteractionMode(InteractionModeFactory.getDefaultLazySelectionMode(network));
		network.setEnableMouseWheelToZoom(false);
		network.setBackground(new ColorBackground(Color.WHITE));

		network.setElementLabelGenerator(new Generator() {
			public Object generate(Object object) {
				Element element = (Element) object;
				return element.getClientProperty("STATE_NAME");
			}
		});
		network.setMovableFilter(new MovableFilter() {
			public boolean isMovable(Element element) {
				return editable;
			}
		});
		network.setResizableFilter(new ResizableFilter() {
			public boolean isResizable(Element element) {
				return editable;
			}
		});
		
		box.addElementPropertyChangeListener(new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent evt) {
				String name = evt.getPropertyName();
				MapNode element = (MapNode) evt.getSource();
				if (name.equals(TWaverConst.PROPERTYNAME_SELECTED)) {
					boolean isSelected = ((Boolean) evt.getNewValue()).booleanValue();
					if (isSelected) {
						element.putCustomDrawFillColor(renderColor.darker());
						element.putCustomDrawOutline3D(true);
						element.putCustomDrawOutlineColor((outlineColor).darker());
						if (!editable) {
							element.addAttachment("stateinfo");
						}
					} else {
						element.putCustomDrawFillColor(renderColor);
						element.putCustomDrawOutline3D(false);
						element.putCustomDrawOutlineColor(outlineColor);
						if (element.containsAttachment("stateinfo")) {
							element.removeAttachment("stateinfo");
						}
					}
				}
			}
		});
		network.getCanvas().addMouseMotionListener(new MouseMotionAdapter() {
			public void mouseMoved(MouseEvent e) {
				if (!editable) {
					MapNode element = (MapNode) network.getElementPhysicalAt(e.getPoint());
					if (element != null && element != lastNode) {
						Point location = element.getCenterLocation();
						Point center = network.getLogicalCenterPoint();
						if (location.x > center.x && location.y < center.y) {
							element.setAttachmentDirection(TWaverConst.ATTACHMENT_DIRECTION_BOTTOM_LEFT);
						}
						else if (location.x > center.x && location.y > center.y) {
							element.setAttachmentDirection(TWaverConst.ATTACHMENT_DIRECTION_TOP_LEFT);
						}
						else if (location.x < center.x && location.y < center.y) {
							element.setAttachmentDirection(TWaverConst.ATTACHMENT_DIRECTION_BOTTOM_RIGHT);
						}
						else {
							element.setAttachmentDirection(TWaverConst.ATTACHMENT_DIRECTION_TOP_RIGHT);
						}
						box.getSelectionModel().setSelection(element);
					}
					if (element == null) {
						box.getSelectionModel().clearSelection();
					}
					lastNode = element;
				}
			}
		});
	}

	public void setOutlineStroke(final int index) {
		final String stroke;
		switch (index) {
		case 0:
			stroke = TWaverConst.STROKE_SOLID_0;
			break;
		case 2:
			stroke = TWaverConst.STROKE_SOLID_2;
			break;
		case 3:
			stroke = TWaverConst.STROKE_SOLID_3;
			break;
		case 4:
			stroke = TWaverConst.STROKE_SOLID_4;
			break;
		case 5:
			stroke = TWaverConst.STROKE_SOLID_5;
			break;
		case 6:
			stroke = TWaverConst.STROKE_SOLID_6;
			break;
		case 7:
			stroke = TWaverConst.STROKE_SOLID_7;
			break;
		case 8:
			stroke = TWaverConst.STROKE_SOLID_8;
			break;
		case 9:
			stroke = TWaverConst.STROKE_SOLID_9;
			break;
		default:
			stroke = TWaverConst.STROKE_SOLID_1;
			break;
		}
		box.iterator(new ElementCallbackHandler() {
			public boolean processElement(Element element) {
				((MapNode) element).putCustomDrawOutlineStroke(stroke);
				return true;
			}
		});
	}
	
	public void setOutlineColor(final Color color) {
		this.outlineColor = color;
		box.iterator(new ElementCallbackHandler() {
			public boolean processElement(Element element) {
				((MapNode) element).putCustomDrawOutlineColor(color);
				return true;
			}
		});
	}
	public Color getOutlineColor() {
		return outlineColor;
	}

	public void setRenderColor(final Color color) {
		this.renderColor = color;
		box.iterator(new ElementCallbackHandler() {
			public boolean processElement(Element element) {
				((MapNode) element).putCustomDrawFillColor(color);
				return true;
			}
		});
	}

	public Color getRenderColor() {
		return renderColor;
	}

	public void setEditable(final boolean editable) {
		this.editable = editable;
		lastNode = null;
		box.iterator(new ElementCallbackHandler() {
			public boolean processElement(Element element) {
				element.putBorderVisible(editable);
				if (element.containsAttachment("stateinfo")) {
					element.removeAttachment("stateinfo");
				}
				return true;
			}
		});
	}
}